/**
 * Clase ProxyManager: Especifica el hilo principal del proxy. Lee la lista de
 * direcciones prohibidas. Posteriormente cicla esperando
 * conexiones remotas, al detectar una, crea otro hilo de tipo Proxy, el cual
 * realiza las funciones de filtrado y comunicación con el servidor web
 *
 * Autores: Christian Chomiak (05-38034)
 *          Miguel De Los Ríos (05-38084)
 */
package kraken;

import java.net.*;
import java.io.*;
import java.util.*;
import javax.xml.stream.*;
import javax.xml.stream.events.*;
import javax.xml.stream.XMLInputFactory;

public class ProxyManager implements Runnable {

    public void run() {
        // Aquí va leer .xml para las páginas prohibidas. Hay que definir
        // la estructura para guardarlo. Hasta ahora se me ocurre List<Ip> o List<url>
        //LeerProhibidas();
        try {
            Hashtable<String, List<String>> prohibidas = LeerProhibidas();
            EscucharConexiones(prohibidas);
        } catch (IOException e) {
            System.err.println("Error al escuchar conexiones.");
            System.exit(1);
        }
    }

    /*
     * Función LeerProhibidas(): Se encarga de leer el archivo .xml con la
     * lista de páginas prohibidas y retorna una hashtable cuyas claves son el
     * ip del servidor y sus valores son sus respectivas listas de subdirectorios
     * prohibidos.
     */
    public Hashtable<String, List<String>> LeerProhibidas() {
        Hashtable<String, List<String>> prohibidas = new Hashtable<String, List<String>>();

        XMLInputFactory inputFactory = XMLInputFactory.newInstance();

        try {
            InputStream input = new FileInputStream(new File("Resources/prohibidas.xml"));
            XMLStreamReader xmlStreamReader = inputFactory.createXMLStreamReader(input);
            String servidor = "";
            List<String> Subdirectorios = new ArrayList<String>();
            String currentElement = "";
            while (xmlStreamReader.hasNext()) {
                int evento = xmlStreamReader.next();
                switch (evento) {
                    case XMLStreamReader.START_ELEMENT:
                        // Se toma el nombre del nuevo elemento (servidor, subdirectorio, etc)
                        currentElement = xmlStreamReader.getLocalName().trim();
                        break;
                    case XMLStreamReader.CHARACTERS:
                        if (currentElement.equals("direccion")) {
                            if(!xmlStreamReader.getText().trim().isEmpty())
                            {
                                /*
                                 * Si el elemento es una dirección, se obtiene el valor
                                 * de la misma y se busca su dirección IP. El substring
                                 * se hace dado que el getByName retorna un string con formato
                                 * hostname/ip.
                                 */
                                String serv = InetAddress.getByName(xmlStreamReader.getText().trim()).toString();
                                servidor = serv.substring(serv.indexOf("/") + 1);
                                Subdirectorios = new ArrayList<String>();
                            }
                        } else if (currentElement.equals("subdirectorio")) {
                            // Si es un subdirectorio se agrega a la lista para ese servidor
                            if(!xmlStreamReader.getText().trim().isEmpty())
                            {
                                String subdir = xmlStreamReader.getText().trim();
                                // Si el ultimo caracter del subdir no es un /, se coloca uno.
                                if(subdir.lastIndexOf("/") != (subdir.length()-1))
                                    subdir += "/";
                                Subdirectorios.add(subdir);
                            }
                        }
                        break;
                    case XMLStreamReader.END_ELEMENT:
                        // Si el elemento que finaliza es un servidor, se agrega la informacion
                        // al hashtable.
                        if (xmlStreamReader.getLocalName().trim().equals("servidor")) {
                            prohibidas.put(servidor, Subdirectorios);
                        }
                        break;
                    default:
                        break;
                }
            }
        } catch (Exception e) {
            System.err.println("No se encuentra el archivo de páginas prohibidas");
            System.exit(1);
        }
        return prohibidas;
    }


    /*
     *  Función EscucharConexiones(): Espera a que algún cliente realice una conexión.
     *  Al detectarla, crea otro hilo que se encargará de manejar ese socket de
     *  cliente específico y esperará a la siguiente conexión
     */
    public void EscucharConexiones(Hashtable<String, List<String>> prohibidas) throws IOException {
        ServerSocket manager = null;
        boolean escuchando = true;
        // Se crea el socket que escucha las conexiones.
        try {
            manager = new ServerSocket(38084);
        } catch (IOException e) {
            System.err.println("Error al crear el socket del manejador");
        }

        Socket clientSocket = null;
        while (escuchando) {
            try {
                clientSocket = manager.accept();
            } catch (IOException e) {
                System.err.println("Error aceptando conexiones de clientes");
                System.exit(1);
            }
            Thread proxy = new Thread(new Proxy(clientSocket, prohibidas));
            proxy.start();
        }
        manager.close();
    }
}
